package xyz.redtorch.node.master.service.impl;

import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import xyz.redtorch.common.constant.CommonConstant;
import xyz.redtorch.common.mongo.MongoDBClient;
import xyz.redtorch.common.service.FastEventService;
import xyz.redtorch.common.service.FastEventService.FastEvent;
import xyz.redtorch.common.service.FastEventService.FastEventDynamicHandlerAbstract;
import xyz.redtorch.common.service.FastEventService.FastEventType;
import xyz.redtorch.common.service.MarketDataService;
import xyz.redtorch.common.util.bar.BarUtils;
import xyz.redtorch.node.db.MongoDBClientService;
import xyz.redtorch.node.master.po.ContractPo;
import xyz.redtorch.node.master.service.MarketDataRecordingService;
import xyz.redtorch.node.master.service.MasterMarketDataRecordingService;
import xyz.redtorch.pb.CoreField.BarField;
import xyz.redtorch.pb.CoreField.TickField;

@Service
public class MasterMarketDataRecordingServiceImpl extends FastEventDynamicHandlerAbstract
		implements MasterMarketDataRecordingService, InitializingBean {
	
	final String COLLECTION_NAME_PREFIX_TICK = "tick_";
	final String COLLECTION_NAME_BAR_1_MIN = "bar_1_min";
	final String COLLECTION_NAME_BAR_3_MIN = "bar_3_min";
	final String COLLECTION_NAME_BAR_5_MIN = "bar_5_min";
	final String COLLECTION_NAME_BAR_15_MIN = "bar_15_min";
	final String COLLECTION_NAME_BAR_1_DAY = "bar_1_day";
	final String COLLECTION_NAME_BAR_5_SEC = "bar_5_sec";

	private static final Logger logger = LoggerFactory.getLogger(MasterMarketDataRecordingServiceImpl.class);

	@Autowired
	private FastEventService fastEventService;

	@Autowired
	private MarketDataService marketDataService;

	@Autowired
	private MarketDataRecordingService marketDataRecordingService;

	private ExecutorService executorService = Executors.newCachedThreadPool();
	
	private ScheduledExecutorService scheduledExecutorService = newSingleThreadScheduledExecutor();
	
	@Autowired
	MongoDBClientService mongoDBClientService;
	
	private MongoDBClient todayMarketDataDBClient;
	private MongoDBClient histMarketDataDBClient;
	private String todayMarketDataDBName;
	private String histMarketDataDBName;

	public void initSetting(MongoDBClient todayMarketDataDBClient, String todayMarketDataDBName, MongoDBClient histMarketDataDBClient, String histMarketDataDBName) {
		this.todayMarketDataDBClient = todayMarketDataDBClient;
		this.todayMarketDataDBName = todayMarketDataDBName;
		this.histMarketDataDBClient = histMarketDataDBClient;
		this.histMarketDataDBName = histMarketDataDBName;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
		initSetting(mongoDBClientService.getMarketDataTodayDBClient(), mongoDBClientService.getMarketDataTodayDBName(), mongoDBClientService.getMarketDataHistDBClient(),
				mongoDBClientService.getMarketDataHistDBName());

		fastEventService.addHandler(this);
		subscribeFastEventType(FastEventType.TICK);

		scheduledExecutorService.scheduleAtFixedRate(() -> {
			try {
				cleanExpiredTodayTickAndBars(marketDataRecordingService.getContractList());
			} catch (Exception e) {
				logger.error("定时清理数据异常", e);
			}
		}, 0, 3, TimeUnit.SECONDS);

	}

	private void cleanExpiredTodayTickAndBars(List<ContractPo> contractList) {
		Document filter = new Document();
		filter.put("actionDay", new Document("$ne", LocalDate.now().format(CommonConstant.D_FORMAT_INT_FORMATTER)));
		for (ContractPo po : contractList) {
			
			String unifiedSymbol = po.getUnifiedSymbol();
			
			List<TickField> expiredTickList = marketDataService.queryTodayTickList(LocalDateTime.now().minusDays(100),
					LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(23, 59, 59)), unifiedSymbol);
			marketDataService.upsertTickListToHistDB(expiredTickList, unifiedSymbol);
			
			List<BarField> expiredBar5SecList = marketDataService.queryTodayBar5SecList(LocalDateTime.now().minusDays(100),
					LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(23, 59, 59)), unifiedSymbol);
			marketDataService.upsertBar5SecListToHistDB(expiredBar5SecList);
			
			List<BarField> expiredBar1MinList = marketDataService.queryTodayBar1MinList(LocalDateTime.now().minusDays(100),
					LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(23, 59, 59)), unifiedSymbol);
			marketDataService.upsertBar1MinListToHistDB(expiredBar1MinList);
			
			List<BarField> expiredBar3MinList = marketDataService.queryTodayBar3MinList(LocalDateTime.now().minusDays(100),
					LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(23, 59, 59)), unifiedSymbol);
			marketDataService.upsertBar3MinListToHistDB(expiredBar3MinList);
			
			List<BarField> expiredBar5MinList = marketDataService.queryTodayBar5MinList(LocalDateTime.now().minusDays(100),
					LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(23, 59, 59)), unifiedSymbol);
			marketDataService.upsertBar5MinListToHistDB(expiredBar5MinList);
			
			List<BarField> expiredBar15MinList = marketDataService.queryTodayBar15MinList(LocalDateTime.now().minusDays(100),
					LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.of(23, 59, 59)), unifiedSymbol);
			marketDataService.upsertBar15MinListToHistDB(expiredBar15MinList);
			
			// 删除今日库里面的非今日数据
			todayMarketDataDBClient.delete(todayMarketDataDBName, COLLECTION_NAME_PREFIX_TICK + unifiedSymbol, filter);
			
		}
		
		todayMarketDataDBClient.delete(todayMarketDataDBName, COLLECTION_NAME_BAR_5_SEC, filter);
		todayMarketDataDBClient.delete(todayMarketDataDBName, COLLECTION_NAME_BAR_1_MIN, filter);
		todayMarketDataDBClient.delete(todayMarketDataDBName, COLLECTION_NAME_BAR_3_MIN, filter);
		todayMarketDataDBClient.delete(todayMarketDataDBName, COLLECTION_NAME_BAR_5_MIN, filter);
		todayMarketDataDBClient.delete(todayMarketDataDBName, COLLECTION_NAME_BAR_15_MIN, filter);
	}

	private void generateAndUpsertTodayBars(TickField tick) {
			List<TickField> tickList = marketDataService.queryTodayTickList(LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 30, 00)), LocalDateTime.of(LocalDate.now(), LocalTime.of(23, 59, 59)), tick.getUnifiedSymbol());
			List<BarField> generateToday5SecBar = BarUtils.generateXSecBar(5, tickList);
			List<BarField> generateToday1MinBar = BarUtils.generate1MinBar(tickList);
			List<BarField> generateToday3MinBar = BarUtils.generateXMinBar(3, generateToday1MinBar);
			List<BarField> generateToday5MinBar = BarUtils.generateXMinBar(5, generateToday1MinBar);
			List<BarField> generateToday15MinBar = BarUtils.generateXMinBar(15, generateToday1MinBar);
			marketDataService.upsertBar5SecListToTodayDB(generateToday5SecBar);
			marketDataService.upsertBar1MinListToTodayDB(generateToday1MinBar);
			marketDataService.upsertBar3MinListToTodayDB(generateToday3MinBar);
			marketDataService.upsertBar5MinListToTodayDB(generateToday5MinBar);
			marketDataService.upsertBar15MinListToTodayDB(generateToday15MinBar);
	}

	@Override
	public void onEvent(FastEvent event, long sequence, boolean endOfBatch) throws Exception {
		if (!subscribedFastEventTypeSet.contains(event.getFastEventType())) {
			return;
		}

		// 判断消息类型
		if (FastEventType.TICK.equals(event.getFastEventType())) {
			try {
				TickField tick = (TickField) event.getObj();
				onTick(tick);
			} catch (Exception e) {
				logger.error("onTick发生异常", e);
			}
		} else {
			logger.warn("未能识别的事件数据类型{}", event.getEvent());
		}

	}

	private void onTick(TickField tick) {
		marketDataService.upsertTickToTodayDB(tick);
		generateAndUpsertTodayBars(tick);
	}

}
